import * as THREE from "three";
// 通过import Three.js 的example来调用其他功能比如加载3D模型和相机参数控制
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js";
import Stats from "three/examples/jsm/libs/stats.module.js";

import shader_pure_vert from "../Shaders/Pure.vert.glsl";
import shader_pure_frag from "../Shaders/Pure.frag.glsl";
import shader_pure_frag_lines from "../Shaders/PureLines.frag.glsl";

import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { contain } from "three/src/extras/TextureUtils";

// 设置 Three.js输出的Canvas画布尺寸
const width = 800;
const height = 600;

const LAYER_GAP = 0.35;

export default class PureWind {
  scene = new THREE.Scene();
  test_geometry = new THREE.BoxGeometry(5, 1, 1);
  test_plane_geomtry: THREE.BufferGeometry;
  test_plane_geomtry_mid: THREE.BufferGeometry;
  test_plane_geomtry_btn: THREE.BufferGeometry;

  // 如果需要定义外观效果 比如颜色 就需要定义材质
  // test_material = new THREE.MeshBasicMaterial( { color: 0xff0000, } );
  test_material: THREE.Material;

  //  test_mesh = new THREE.Mesh( this.test_geometry, this.test_material );
  test_mesh: THREE.Mesh;
  test_box3: THREE.Box3;

  // test_camera = new THREE.PerspectiveCamera(/*Fov*/45, /*Width/Heigth*/width/height, /*Near*/0.1, /*Far*/1000 );
  //  test_mesh = new THREE.Mesh( this.test_geometry, this.test_material );
  // test_material = new THREE.MeshBasicMaterial( { color: 0xff0000, } );
  test_camera: THREE.PerspectiveCamera;

  test_render: THREE.WebGLRenderer;

  test_orbitcontrols: OrbitControls;

  test_light: THREE.Light;
  test_ambientLight: THREE.Light;
  test_stats: Stats;
  test_gui: GUI;

  // 纹理
  test_texture_loader: THREE.TextureLoader;
  test_texture_layer1: THREE.Texture;
  test_texture_layer2: THREE.Texture;
  test_texture_layer3: THREE.Texture;
  test_texture_sides: THREE.Texture;
  test_vert_texture: THREE.Texture;
  test_custom_shader_material_top: THREE.ShaderMaterial;
  test_custom_shader_material_mid: THREE.ShaderMaterial;
  test_custom_shader_material_btm: THREE.ShaderMaterial;
  test_clock: THREE.Clock;

  test_color: THREE.Color;

  // parameters
  wind_parameters: {
    quantity: number;
    isRotate: boolean;
  };

  test_input_percent_x: number = 0;
  test_input_percent_y: number = 0;

  constructor(container: HTMLElement) {
    // ******************* 渲染器初始化 *******************
    const initialWidth = container.clientWidth;
    const initialHeight = container.clientHeight;
    this.test_render = new THREE.WebGLRenderer({
      antialias: true,
      powerPreference: "low-power",
      alpha: true,
    });
    this.test_render.setClearColor(0x000000, 0); // 不透明黑色
    this.test_render.setSize(initialWidth, initialHeight);
    this.test_render.setPixelRatio(window.devicePixelRatio);
    // this.test_render.setClearColor(0xffffff, 0);

    // ******************* 纹理加载器初始化 *******************
    this.test_texture_loader = new THREE.TextureLoader();

    // ******************* 基础几何体与材质初始化 *******************
    this.test_material = new THREE.MeshStandardMaterial({
      color: 0x048ef4,
      roughness: 0.55,
      metalness: 0.1,
      flatShading: false,
    });

    this.test_mesh = new THREE.Mesh(this.test_geometry, this.test_material);
    this.test_mesh.position.set(0, 1, 0);

    // ******************* 相机初始化 *******************
    this.test_camera = new THREE.PerspectiveCamera(
      40,
      width / height,
      0.1,
      1000
    );
    this.test_camera.position.set(-0.85, 6.45, 26.83);
    this.test_camera.rotation.set(-0.236, -0.031, -0.007);
    this.test_camera.lookAt(this.test_mesh.position);

    // ******************* 光源初始化 *******************
    this.test_light = new THREE.PointLight(0xffffff, 2, 100, 0.05);
    this.test_light.position.set(0, 10, 10);
    this.scene.add(this.test_light);

    this.test_ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
    this.scene.add(this.test_ambientLight);

    // ******************* 颜色初始化 *******************
    this.test_color = new THREE.Color();
    this.test_color.setHex(0xffffff);

    // ******************* 渲染器 DOM 挂载 *******************
    container.innerHTML = "";
    container.appendChild(this.test_render.domElement);

    // ******************* 帧率监控 *******************
    this.test_stats = new Stats();
    // document.body.appendChild(this.test_stats.dom);

    // ******************* 平面与Shader材质创建 *******************
    this.CreatePlane();

    // ******************* 首帧渲染 *******************
    this.test_render.render(this.scene, this.test_camera);
  }

  // ******************* 动画与参数更新 *******************
  update() {
    const elapsedTime = this.test_clock.getElapsedTime();

    this.test_custom_shader_material_top.uniforms.iTime.value =
      elapsedTime;
    this.test_custom_shader_material_top.uniforms.iPercentX.value =
      this.test_input_percent_x;
    this.test_custom_shader_material_top.uniforms.iPercentY.value =
      this.test_input_percent_y;

    this.test_custom_shader_material_mid.uniforms.iTime.value =
    elapsedTime;
    this.test_custom_shader_material_mid.uniforms.iPercentX.value =
      this.test_input_percent_x;
    this.test_custom_shader_material_mid.uniforms.iPercentY.value =
      this.test_input_percent_y;

    this.test_custom_shader_material_btm.uniforms.iTime.value =
    elapsedTime;
    this.test_custom_shader_material_btm.uniforms.iPercentX.value =
      this.test_input_percent_x;
    this.test_custom_shader_material_btm.uniforms.iPercentY.value =
      this.test_input_percent_y;

    this.test_stats.update();
    this.test_render.render(this.scene, this.test_camera);
  }

  // ******************* 窗口自适应 *******************
  resize(w: number, h: number) {
    this.test_render.setSize(w, h);
    this.test_camera.aspect = w / h;
    this.test_camera.updateProjectionMatrix();

    if (
      this.test_custom_shader_material_top &&
      this.test_custom_shader_material_btm
    ) {
      this.test_custom_shader_material_top.uniforms.iResolution.value.set(w, h);
      this.test_custom_shader_material_btm.uniforms.iResolution.value.set(w, h);
      console.log("resize: ", w, h);
    }
  }

  // ******************* 防止内存泄漏的释放函数 *******************
  dispose() {
    // 释放几何体
    this.test_geometry?.dispose();
    this.test_plane_geomtry?.dispose();
    this.test_plane_geomtry_mid?.dispose();
    this.test_plane_geomtry_btn?.dispose();

    // 释放材质
    this.test_material?.dispose();
    this.test_custom_shader_material_top?.dispose();
    this.test_custom_shader_material_mid?.dispose();
    this.test_custom_shader_material_btm?.dispose();

    // 释放纹理
    this.test_texture_layer1?.dispose();
    this.test_texture_layer2?.dispose();
    this.test_texture_layer3?.dispose();
    this.test_texture_sides?.dispose();
    // this.test_vert_texture?.dispose();

    // 移除渲染器 DOM
    if (
      this.test_render &&
      this.test_render.domElement &&
      this.test_render.domElement.parentNode
    ) {
      this.test_render.domElement.parentNode.removeChild(
        this.test_render.domElement
      );
    }

    // 移除 stats 面板
    if (
      this.test_stats &&
      this.test_stats.dom &&
      this.test_stats.dom.parentNode
    ) {
      this.test_stats.dom.parentNode.removeChild(this.test_stats.dom);
    }

    // 移除 GUI
    if (
      this.test_gui &&
      this.test_gui.domElement &&
      this.test_gui.domElement.parentNode
    ) {
      this.test_gui.domElement.parentNode.removeChild(this.test_gui.domElement);
    }

    // 清空场景
    if (this.scene) {
      // 移除所有子对象
      while (this.scene.children.length > 0) {
        const child = this.scene.children[0];
        this.scene.remove(child);
        // 如果是Mesh，释放其几何体和材质
        if ((child as THREE.Mesh).geometry) {
          (child as THREE.Mesh).geometry.dispose();
        }
        if ((child as THREE.Mesh).material) {
          // 可能是数组
          const material = (child as THREE.Mesh).material;
          if (Array.isArray(material)) {
            material.forEach((mat) => mat.dispose && mat.dispose());
          } else {
            material.dispose && material.dispose();
          }
        }
      }
    }
  }

  // ******************* 纹理加载 *******************
  LoadTexture() {
    // this.test_vert_texture = this.test_texture_loader.load(
    //   "img/Date0422_VerticalTexture.png"
    // );
    this.test_texture_layer1 = this.test_texture_loader.load(
      "img/Date0422_Layer_1.jpg"
    );
    this.test_texture_layer1.wrapS = THREE.RepeatWrapping;
    this.test_texture_layer1.wrapT = THREE.RepeatWrapping;
    
    this.test_texture_layer2 = this.test_texture_loader.load(
      "img/Date0422_Layer2.jpg"
    );
    this.test_texture_layer2.wrapS = THREE.RepeatWrapping;
    this.test_texture_layer2.wrapT = THREE.RepeatWrapping;
    this.test_texture_layer3 = this.test_texture_loader.load(
      "img/SplitLines0513.png"
    );
    this.test_texture_layer3.wrapS = THREE.RepeatWrapping;
    this.test_texture_layer3.wrapT = THREE.RepeatWrapping;
    this.test_texture_sides = this.test_texture_loader.load("img/mask.png");
  }

  // ******************* Shader参数初始化 *******************
  LoadShaderParameter() {
    this.test_clock = new THREE.Clock();
    const currentSize = new THREE.Vector2();
    this.test_render.getSize(currentSize);
  }

  // ******************* 平面与Shader材质创建 *******************
  CreatePlane() {
    this.LoadShaderParameter();
    this.LoadTexture();

    // THREE.js 自带的几何顶点数据;   PlaneGeometry 参数: width, height, widthSegments, heightSegments
    const plane_width = 5;
    const plane_height = 10;
    const plane_width_segment = 15;
    const plane_height_segment = 15;
    this.test_plane_geomtry = new THREE.PlaneGeometry(
      plane_width,
      plane_height,
      plane_width_segment,
      plane_height_segment
    );
    this.test_plane_geomtry_mid = new THREE.PlaneGeometry(
      plane_width,
      plane_height,
      plane_width_segment,
      plane_height_segment
    );
    this.test_plane_geomtry_btn = new THREE.PlaneGeometry(
      plane_width,
      plane_height,
      plane_width_segment,
      plane_height_segment
    );

    // 绕X轴旋转90度, 使平面垂直于地面
    this.test_plane_geomtry.rotateX(-Math.PI / 2);
    this.test_plane_geomtry_mid.rotateX(-Math.PI / 2);
    this.test_plane_geomtry_btn.rotateX(-Math.PI / 2);

    // ************** 材质 **************
    // 注意颜色写法
    // const geom_plane_color = new THREE.Color(0x0000ff);
    // const geom_plane_color = new THREE.Color();
    // geom_plane_color.r = Math.random();
    // geom_plane_color.g = Math.random();
    // geom_plane_color.b = Math.random();

    // 平面的材质
    // const geom_plane_material = new THREE.MeshLambertMaterial({
    //   color: geom_plane_color,
    //   wireframe: true, // 使能线框模式
    //   side: THREE.DoubleSide,
    // });
    // ************** 材质 **************

    // ************** ShaderMaterial **************
    // this.test_box3 = new THREE.Box3();
    // this.test_box3.setFromObject(this.test_mesh);
    // const boundsMin = this.test_box3.min;
    // const boundsMax = this.test_box3.max;
    const makeShaderMaterial = (
      mainTexture: THREE.Texture,
      frag: string,
      uPhase: number,
      uFrequency: number,
      boundsMax: THREE.Vector3,
      boundsMin: THREE.Vector3
    ) => {
      return new THREE.ShaderMaterial({
        vertexShader: shader_pure_vert,
        fragmentShader: frag,
        uniforms: {
          uPhase: { value: uPhase },
          uFrequency: { value: uFrequency },
          uBoundsMin: {
            value: boundsMin.clone(),
          },
          uBoundsMax: {
            value: boundsMax.clone(),
          },
          iResolution: {
            value: new THREE.Vector2(
              this.test_render.domElement.width,
              this.test_render.domElement.height
            ),
          },
          iPercentX: { value: 3.3 },
          iPercentY: { value: 3.3 },
          uAmplitude: { value: 1.4 },
          uColor: { value: new THREE.Color(1.0, 1.0, 1.0) },
          iTime: { value: 0.0 },
          uv_mid: { value: mainTexture },
          uv_out: { value: this.test_texture_layer3 },
          uv_head_tail: { value: this.test_texture_sides },
          uv_sides: { value: this.test_texture_sides },
        //   uv_vert: { value: this.test_vert_texture },
        },
        side: THREE.DoubleSide,
        transparent: true,
        depthWrite: false, // 关闭深度测试 防止上层覆盖下层( 深度测试即根据渲染的位置来判断是否被阻挡 阻挡则不显示 )
        depthTest: false,
      });
    };
    // ************** 平面的网格模型 **************
    const geom_plane_mesh = new THREE.Mesh(
        this.test_plane_geomtry
        //   this.test_custom_shader_material
      );
      geom_plane_mesh.name = "layer_top";
      // ------------
      const geom_plane_mesh_mid = new THREE.Mesh(
        this.test_plane_geomtry_mid
        //   this.test_custom_shader_material
      );
      geom_plane_mesh_mid.name = "layer_mid";
      // ------------
      // this.test_custom_shader_material.fragmentShader = shader_pure_frag_lines;
      const geom_plane_mesh_btn = new THREE.Mesh(
        this.test_plane_geomtry_btn
        //   this.test_custom_shader_material
      );
      geom_plane_mesh_btn.name = "layer_btn";
      // ------------

    // ************** 获取包围盒 **************
    this.test_box3 = new THREE.Box3();
    this.test_box3.setFromObject(geom_plane_mesh);
    const _boundsMin = this.test_box3.min;
    const _boundsMax = this.test_box3.max;
    
    this.test_custom_shader_material_top = makeShaderMaterial(
      this.test_texture_layer1,
      shader_pure_frag,
      0.0, // 顶层相位
      3.5, // 顶层频率
    _boundsMax,
    _boundsMin
    );

    this.test_custom_shader_material_mid = makeShaderMaterial(
      this.test_texture_layer2,
      shader_pure_frag,
      4.0,
      1.5,
      _boundsMax,
      _boundsMin
    );

    this.test_custom_shader_material_btm = makeShaderMaterial(
      this.test_texture_layer3,
      shader_pure_frag_lines,
      3.0,
      0.5,
      _boundsMax,
      _boundsMin
    );
    // ************** ShaderMaterial **************



    // group 等价于 Object3D
    const geom_plane_group = new THREE.Group();
    geom_plane_group.name = "wind_group";
    geom_plane_group.add(geom_plane_mesh);
    geom_plane_group.add(geom_plane_mesh_mid);
    geom_plane_group.add(geom_plane_mesh_btn);

    // ************** 平面的网格模型 **************

    // ************** Group旋转 **************
    // 创建欧拉角进行旋转
    const _rotateEuler = new THREE.Euler();
    _rotateEuler.x = -Math.PI / 2;
    // _rotateEuler.z = Math.PI / 2;
    // geom_plane_mesh.setRotationFromEuler(_rotateEuler);
    // geom_plane_group.setRotationFromEuler(_rotateEuler);
    // 或者直接调用 Mesh 的旋转方法
    // geom_plane_mesh.rotateZ(Math.PI / 2);
    // geom_plane_group.rotateZ(Math.PI / 2);
    // ************** Group旋转 **************

    // // ************** Group分别平移 **************
    // geom_plane_mesh.position.set(0, 0, 0);
    // 遍历 Group 的子对象, 并分别设置位置
    // 先把Group添加到场景中 再获取子对象的世界坐标
    this.scene.add(geom_plane_group);
    geom_plane_group.traverse((child) => {
      if (child instanceof THREE.Mesh) {
        console.log("child.name: ", child.name);
        // child.setRotationFromEuler(_rotateEuler);

        // 添加局部Axis 可见在旋转之后局部坐标系也会旋转 跟Group的坐标系不一致
        // const axisHelper = new THREE.AxesHelper(1);
        // child.add(axisHelper);
        // child.material = this.test_custom_shader_material;

        if (child.name === "layer_top") {
          child.position.set(0, LAYER_GAP, 0);
          child.material = this.test_custom_shader_material_top;
        } else if (child.name === "layer_mid") {
          child.position.set(0, 0, 0);
          child.material = this.test_custom_shader_material_mid;
        } else if (child.name === "layer_btn") {
          child.position.set(0, -LAYER_GAP, 0);
          child.material = this.test_custom_shader_material_btm;
        }

        geom_plane_group.updateMatrixWorld(true);
        // 获取子对象的世界坐标
        let worldPosition = new THREE.Vector3();
        child.getWorldPosition(worldPosition);
        console.log(
          child.name,
          "----- Local Position",
          child.position,
          "---- World Position",
          worldPosition
        );
      }
    });

    // console.log("顶点位置数据: ", this.test_plane_geomtry.attributes.position);
  }
}
